#include "CodeStream.h"

CodeStream::CodeStream()
{
	m_readpos = 0;
	m_line = 0;
	m_cols = 0;
	m_srclen = 0;
}

void CodeStream::reset()
{
	m_src  = "";
	m_line = 0;
	m_cols = 0;
	m_srclen = 0;
	m_readpos = 0;
}

void CodeStream::add_source(const std::string& str)
{
	m_src += "\n";
	m_src += str;
	m_srclen = (int)m_src.length();
}

bool CodeStream::is_space(char c)
{
	return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}

std::string CodeStream::trim(const std::string& s)
{
	std::string ret;

	bool lastSpace = true;
	for(size_t i = 0; i < s.length(); ++i)
	{
		if(is_space(s[i]))
		{
			if(lastSpace)
			{
				continue;
			}

			lastSpace = true;

			for(size_t j = i; j < s.length(); ++j)
			{
				if(!is_space(s[j]))
				{
					ret += ' ';
					break;
				}
			}
		}
		else
		{
			lastSpace = false;
			ret += s[i];
		}
	}

	return ret;
}

int CodeStream::get_curline()
{
	return m_line;
}

int CodeStream::get_curcols()
{
	return m_cols;
}

bool CodeStream::is_start_with(char h)
{
	return char_at(0) == h;
}

bool CodeStream::is_start_with(char h1, char h2)
{
	return char_at(0) == h1 &&
		char_at(1) == h2;
}

bool CodeStream::is_start_with(char h1, char h2, char h3)
{
	return char_at(0) == h1 &&
		char_at(1) == h2 &&
		char_at(2) == h3;
}

bool CodeStream::get_text(char e, int offset, std::string& ret, bool accept_line_end, bool accept_stream_end)
{
	int endpos = m_readpos + offset;

	for(; endpos < m_srclen; ++endpos)
	{
		if(m_src[endpos] == e)
		{
			ret = m_src.substr(m_readpos + offset, endpos - m_readpos - offset);
			skipto(endpos + 2);
			return true;
		}

		if(accept_line_end && (m_src[endpos] == '\r' || m_src[endpos] == '\n'))
		{
			ret = m_src.substr(m_readpos + offset, endpos - m_readpos - offset);
			skipto(endpos + 1);
			return true;
		}
	}

	if(accept_stream_end)
	{
		ret = m_src.substr(m_readpos + offset);
		skipto(endpos);
		return true;
	}

	return false;
}

bool CodeStream::get_text(char e1, char e2, int offset, std::string& ret, bool accept_line_end, bool accept_stream_end)
{
	int endpos = m_readpos + offset;

	for(; endpos + 1 < m_srclen; ++endpos)
	{
		if(m_src[endpos] == e1 && m_src[endpos + 1] == e2)
		{
			ret = m_src.substr(m_readpos + offset, endpos - m_readpos - offset);
			skipto(endpos + 3);
			return true;
		}

		if(accept_line_end && (m_src[endpos] == '\r' || m_src[endpos] == '\n'))
		{
			ret = m_src.substr(m_readpos + offset, endpos - m_readpos - offset);
			skipto(endpos + 1);
			return true;
		}
	}

	if(accept_stream_end)
	{
		ret = m_src.substr(m_readpos + offset);
		skipto(endpos);
		return true;
	}

	return false;
}

bool CodeStream::get_text(char e1, char e2, char e3, int offset, std::string& ret, bool accept_line_end, bool accept_stream_end )
{
	int endpos = m_readpos + offset;

	for(; endpos + 2 < m_srclen; ++endpos)
	{
		if(m_src[endpos] == e1 && m_src[endpos + 1] == e2 && m_src[endpos + 2] == e3)
		{
			ret = m_src.substr(m_readpos + offset, endpos - m_readpos - offset);
			skipto(endpos + 4);
			return true;
		}

		if(accept_line_end && (m_src[endpos] == '\r' || m_src[endpos] == '\n'))
		{
			ret = m_src.substr(m_readpos + offset, endpos - m_readpos - offset);
			skipto(endpos + 1);
			return true;
		}
	}

	if(accept_stream_end)
	{
		ret = m_src.substr(m_readpos + offset);
		skipto(endpos);
		return true;
	}

	return false;
}

bool CodeStream::is_end()
{
	return m_readpos >= m_srclen;
}

bool CodeStream::skip(int n)
{
	while(n > 0 && m_readpos < m_srclen)
	{
		if(m_src[m_readpos] == '\n')
		{
			++m_line;
			m_cols = 0;
		}

		++m_readpos;
		--n;
		++m_cols;
	}

	return n <= 0;
}

bool CodeStream::skipto(int pos)
{
	if(pos < m_readpos)
		return false;

	if(pos > m_srclen)
	{
		pos = m_srclen;
	}

	while(m_readpos < pos)
	{
		if(m_src[m_readpos] == '\n')
		{
			++m_line;
			m_cols = 0;
		}

		++m_readpos;
		++m_cols;
	}

	return true;
}

char CodeStream::get()
{
	if(m_readpos >= m_srclen)
		return 0;

	char c = m_src[m_readpos++];
	while(c == '\r' && m_readpos < m_srclen)
	{
		c = m_src[m_readpos++];
	}

	if(c == '\r')
		return 0;

	if(c == '\n')
	{
		m_line++;
		m_cols = 0;
	}

	++m_cols;
	return c;
}

char CodeStream::char_at(int offset)
{
	if(m_readpos + offset >= m_srclen)
		return 0;

	return m_src[m_readpos + offset];
}
